home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / modelers / geomview / source.lha / Geomview / src / bin / animate / glob.c < prev    next >
C/C++ Source or Header  |  1992-08-31  |  11KB  |  701 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)glob.c    5.7 (Berkeley) 12/14/88";
  20. #endif /* not lint */
  21.  
  22. /*
  23.  * C-shell glob for random programs.
  24.  */
  25.  
  26. #include <sys/param.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include <dirent.h>
  30.  
  31. #include <stdio.h>
  32. #include <errno.h>
  33. #include <pwd.h>
  34.  
  35. #define    QUOTE 0200
  36. #define    TRIM 0177
  37. #define    eq(a,b)        (strcmp(a, b)==0)
  38. #define    GAVSIZ        (NCARGS/6)
  39. #define    isdir(d)    ((d.st_mode & S_IFMT) == S_IFDIR)
  40.  
  41. static    char **gargv;        /* Pointer to the (stack) arglist */
  42. static    int gargc;        /* Number args in gargv */
  43. static    int gnleft;
  44. static    short gflag;
  45. static    int tglob();
  46. char    **glob();
  47. static  rscan(register char **, int ());
  48. static  ginit(char **);
  49. static  collect(register char *);
  50. static  acollect(register char *);
  51. static  sort();
  52. static  expand(char *);
  53. static  matchdir(char *);
  54. static  execbrc(char *, char *);
  55. static  match(char *, char *);
  56. static  amatch(register char *, char *);
  57. static  Gmatch(register char *, char *);
  58. static  Gcat(register char *, char *);
  59. static  addpath(char);
  60. static  fatal(char *);
  61. static  scan(register char **, int ());
  62. char    *globerr;
  63. char    *home;
  64. struct    passwd *getpwnam();
  65. extern    int errno;
  66. static    char *strspl(), *strend();
  67. char    *malloc(), *strcpy(), *strcat();
  68. char    **copyblk();
  69.  
  70. static    int globcnt;
  71.  
  72. char    *globchars = "`{[*?";
  73.  
  74. static    char *gpath, *gpathp, *lastgpathp;
  75. static    int globbed;
  76. static    char *entp;
  77. static    char **sortbas;
  78.  
  79. char **
  80. glob(v)
  81.     register char *v;
  82. {
  83.     char agpath[BUFSIZ];
  84.     char *agargv[GAVSIZ];
  85.     char *vv[2];
  86.     vv[0] = v;
  87.     vv[1] = 0;
  88.     gflag = 0;
  89.     rscan(vv, tglob);
  90.     if (gflag == 0)
  91.         return (copyblk(vv));
  92.  
  93.     globerr = 0;
  94.     gpath = agpath; gpathp = gpath; *gpathp = 0;
  95.     lastgpathp = &gpath[sizeof agpath - 2];
  96.     ginit(agargv); globcnt = 0;
  97.     collect(v);
  98.     if (globcnt == 0 && (gflag&1)) {
  99.         blkfree(gargv), gargv = 0;
  100.         return (0);
  101.     } else
  102.         return (gargv = copyblk(gargv));
  103. }
  104.  
  105. static
  106. ginit(agargv)
  107.     char **agargv;
  108. {
  109.  
  110.     agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
  111.     gnleft = NCARGS - 4;
  112. }
  113.  
  114. static
  115. collect(as)
  116.     register char *as;
  117. {
  118.     if (eq(as, "{") || eq(as, "{}")) {
  119.         Gcat(as, "");
  120.         sort();
  121.     } else
  122.         acollect(as);
  123. }
  124.  
  125. static
  126. acollect(as)
  127.     register char *as;
  128. {
  129.     register int ogargc = gargc;
  130.  
  131.     gpathp = gpath; *gpathp = 0; globbed = 0;
  132.     expand(as);
  133.     if (gargc != ogargc)
  134.         sort();
  135. }
  136.  
  137. static
  138. sort()
  139. {
  140.     register char **p1, **p2, *c;
  141.     char **Gvp = &gargv[gargc];
  142.  
  143.     p1 = sortbas;
  144.     while (p1 < Gvp-1) {
  145.         p2 = p1;
  146.         while (++p2 < Gvp)
  147.             if (strcmp(*p1, *p2) > 0)
  148.                 c = *p1, *p1 = *p2, *p2 = c;
  149.         p1++;
  150.     }
  151.     sortbas = Gvp;
  152. }
  153.  
  154. static
  155. expand(as)
  156.     char *as;
  157. {
  158.     register char *cs;
  159.     register char *sgpathp, *oldcs;
  160.     struct stat stb;
  161.  
  162.     sgpathp = gpathp;
  163.     cs = as;
  164.     if (*cs == '~' && gpathp == gpath) {
  165.         addpath('~');
  166.         for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
  167.             addpath(*cs++);
  168.         if (!*cs || *cs == '/') {
  169.             if (gpathp != gpath + 1) {
  170.                 *gpathp = 0;
  171.                 if (gethdir(gpath + 1))
  172.                     globerr = "Unknown user name after ~";
  173.                 (void) strcpy(gpath, gpath + 1);
  174.             } else {
  175.                 if(home == NULL) {
  176.                     struct passwd *pp;
  177.                     extern char *getenv();
  178.  
  179.                     home = getenv("HOME");
  180.                     if(home == NULL) {
  181.                     pp = getpwuid(getuid());
  182.                     if(pp != NULL)
  183.                         home = pp->pw_dir;
  184.                     }
  185.                 }
  186.                 if(home == NULL) {
  187.                     home = "";
  188.                     globerr = "Can't determine own home directory";
  189.                 } else {
  190.                     (void) strcpy(gpath, home);
  191.                 }
  192.             }
  193.             gpathp = strend(gpath);
  194.         }
  195.     }
  196.     while (!any(*cs, globchars)) {
  197.         if (*cs == 0) {
  198.             if (!globbed)
  199.                 Gcat(gpath, "");
  200.             else if (stat(gpath, &stb) >= 0) {
  201.                 Gcat(gpath, "");
  202.                 globcnt++;
  203.             }
  204.             goto endit;
  205.         }
  206.         addpath(*cs++);
  207.     }
  208.     oldcs = cs;
  209.     while (cs > as && *cs != '/')
  210.         cs--, gpathp--;
  211.     if (*cs == '/')
  212.         cs++, gpathp++;
  213.     *gpathp = 0;
  214.     if (*oldcs == '{') {
  215.         (void) execbrc(cs, ((char *)0));
  216.         return;
  217.     }
  218.     matchdir(cs);
  219. endit:
  220.     gpathp = sgpathp;
  221.     *gpathp = 0;
  222. }
  223.  
  224. static
  225. matchdir(pattern)
  226.     char *pattern;
  227. {
  228.     struct stat stb;
  229.     register struct dirent *dp;
  230.     DIR *dirp;
  231.  
  232.     dirp = opendir(gpath[0] == '\0' ? "." : gpath);
  233.     if (dirp == NULL) {
  234.         if (globbed)
  235.             return;
  236.         goto patherr2;
  237.     }
  238.     if (fstat(dirp->dd_fd, &stb) < 0)
  239.         goto patherr1;
  240.     if (!isdir(stb)) {
  241.         errno = ENOTDIR;
  242.         goto patherr1;
  243.     }
  244.     while ((dp = readdir(dirp)) != NULL) {
  245.         if (dp->d_ino == 0)
  246.             continue;
  247.         if (match(dp->d_name, pattern)) {
  248.             Gcat(gpath, dp->d_name);
  249.             globcnt++;
  250.         }
  251.     }
  252.     closedir(dirp);
  253.     return;
  254.  
  255. patherr1:
  256.     closedir(dirp);
  257. patherr2:
  258.     globerr = "Bad directory components";
  259. }
  260.  
  261. static
  262. execbrc(p, s)
  263.     char *p, *s;
  264. {
  265.     char restbuf[BUFSIZ + 2];
  266.     register char *pe, *pm, *pl;
  267.     int brclev = 0;
  268.     char *lm, savec, *sgpathp;
  269.  
  270.     for (lm = restbuf; *p != '{'; *lm++ = *p++)
  271.         continue;
  272.     for (pe = ++p; *pe; pe++)
  273.     switch (*pe) {
  274.  
  275.     case '{':
  276.         brclev++;
  277.         continue;
  278.  
  279.     case '}':
  280.         if (brclev == 0)
  281.             goto pend;
  282.         brclev--;
  283.         continue;
  284.  
  285.     case '[':
  286.         for (pe++; *pe && *pe != ']'; pe++)
  287.             continue;
  288.         continue;
  289.     }
  290. pend:
  291.     brclev = 0;
  292.     for (pl = pm = p; pm <= pe; pm++)
  293.     switch (*pm & (QUOTE|TRIM)) {
  294.  
  295.     case '{':
  296.         brclev++;
  297.         continue;
  298.  
  299.     case '}':
  300.         if (brclev) {
  301.             brclev--;
  302.             continue;
  303.         }
  304.         goto doit;
  305.  
  306.     case ','|QUOTE:
  307.     case ',':
  308.         if (brclev)
  309.             continue;
  310. doit:
  311.         savec = *pm;
  312.         *pm = 0;
  313.         (void) strcpy(lm, pl);
  314.         (void) strcat(restbuf, pe + 1);
  315.         *pm = savec;
  316.         if (s == 0) {
  317.             sgpathp = gpathp;
  318.             expand(restbuf);
  319.             gpathp = sgpathp;
  320.             *gpathp = 0;
  321.         } else if (amatch(s, restbuf))
  322.             return (1);
  323.         sort();
  324.         pl = pm + 1;
  325.         if (brclev)
  326.             return (0);
  327.         continue;
  328.  
  329.     case '[':
  330.         for (pm++; *pm && *pm != ']'; pm++)
  331.             continue;
  332.         if (!*pm)
  333.             pm--;
  334.         continue;
  335.     }
  336.     if (brclev)
  337.         goto doit;
  338.     return (0);
  339. }
  340.  
  341. static
  342. match(s, p)
  343.     char *s, *p;
  344. {
  345.     register int c;
  346.     register char *sentp;
  347.     char sglobbed = globbed;
  348.  
  349.     if (*s == '.' && *p != '.')
  350.         return (0);
  351.     sentp = entp;
  352.     entp = s;
  353.     c = amatch(s, p);
  354.     entp = sentp;
  355.     globbed = sglobbed;
  356.     return (c);
  357. }
  358.  
  359. static
  360. amatch(s, p)
  361.     register char *s, *p;
  362. {
  363.     register int scc;
  364.     int ok, lc;
  365.     char *sgpathp;
  366.     struct stat stb;
  367.     int c, cc;
  368.  
  369.     globbed = 1;
  370.     for (;;) {
  371.         scc = *s++ & TRIM;
  372.         switch (c = *p++) {
  373.  
  374.         case '{':
  375.             return (execbrc(p - 1, s - 1));
  376.  
  377.         case '[':
  378.             ok = 0;
  379.             lc = 077777;
  380.             while (cc = *p++) {
  381.                 if (cc == ']') {
  382.                     if (ok)
  383.                         break;
  384.                     return (0);
  385.                 }
  386.                 if (cc == '-') {
  387.                     if (lc <= scc && scc <= *p++)
  388.                         ok++;
  389.                 } else
  390.                     if (scc == (lc = cc))
  391.                         ok++;
  392.             }
  393.             if (cc == 0)
  394.                 if (ok)
  395.                     p--;
  396.                 else
  397.                     return 0;
  398.             continue;
  399.  
  400.         case '*':
  401.             if (!*p)
  402.                 return (1);
  403.             if (*p == '/') {
  404.                 p++;
  405.                 goto slash;
  406.             }
  407.             s--;
  408.             do {
  409.                 if (amatch(s, p))
  410.                     return (1);
  411.             } while (*s++);
  412.             return (0);
  413.  
  414.         case 0:
  415.             return (scc == 0);
  416.  
  417.         default:
  418.             if (c != scc)
  419.                 return (0);
  420.             continue;
  421.  
  422.         case '?':
  423.             if (scc == 0)
  424.                 return (0);
  425.             continue;
  426.  
  427.         case '/':
  428.             if (scc)
  429.                 return (0);
  430. slash:
  431.             s = entp;
  432.             sgpathp = gpathp;
  433.             while (*s)
  434.                 addpath(*s++);
  435.             addpath('/');
  436.             if (stat(gpath, &stb) == 0 && isdir(stb))
  437.                 if (*p == 0) {
  438.                     Gcat(gpath, "");
  439.                     globcnt++;
  440.                 } else
  441.                     expand(p);
  442.             gpathp = sgpathp;
  443.             *gpathp = 0;
  444.             return (0);
  445.         }
  446.     }
  447. }
  448.  
  449. static
  450. Gmatch(s, p)
  451.     register char *s, *p;
  452. {
  453.     register int scc;
  454.     int ok, lc;
  455.     int c, cc;
  456.  
  457.     for (;;) {
  458.         scc = *s++ & TRIM;
  459.         switch (c = *p++) {
  460.  
  461.         case '[':
  462.             ok = 0;
  463.             lc = 077777;
  464.             while (cc = *p++) {
  465.                 if (cc == ']') {
  466.                     if (ok)
  467.                         break;
  468.                     return (0);
  469.                 }
  470.                 if (cc == '-') {
  471.                     if (lc <= scc && scc <= *p++)
  472.                         ok++;
  473.                 } else
  474.                     if (scc == (lc = cc))
  475.                         ok++;
  476.             }
  477.             if (cc == 0)
  478.                 if (ok)
  479.                     p--;
  480.                 else
  481.                     return 0;
  482.             continue;
  483.  
  484.         case '*':
  485.             if (!*p)
  486.                 return (1);
  487.             for (s--; *s; s++)
  488.                 if (Gmatch(s, p))
  489.                     return (1);
  490.             return (0);
  491.  
  492.         case 0:
  493.             return (scc == 0);
  494.  
  495.         default:
  496.             if ((c & TRIM) != scc)
  497.                 return (0);
  498.             continue;
  499.  
  500.         case '?':
  501.             if (scc == 0)
  502.                 return (0);
  503.             continue;
  504.  
  505.         }
  506.     }
  507. }
  508.  
  509. static
  510. Gcat(s1, s2)
  511.     register char *s1, *s2;
  512. {
  513.     register int len = strlen(s1) + strlen(s2) + 1;
  514.  
  515.     if (len >= gnleft || gargc >= GAVSIZ - 1)
  516.         globerr = "Arguments too long";
  517.     else {
  518.         gargc++;
  519.         gnleft -= len;
  520.         gargv[gargc] = 0;
  521.         gargv[gargc - 1] = strspl(s1, s2);
  522.     }
  523. }
  524.  
  525. static
  526. addpath(char c)
  527. {
  528.  
  529.     if (gpathp >= lastgpathp)
  530.         globerr = "Pathname too long";
  531.     else {
  532.         *gpathp++ = c;
  533.         *gpathp = 0;
  534.     }
  535. }
  536.  
  537. static
  538. rscan(t, f)
  539.     register char **t;
  540.     int (*f)();
  541. {
  542.     register char *p, c;
  543.  
  544.     while (p = *t++) {
  545.         if (f == tglob)
  546.             if (*p == '~')
  547.                 gflag |= 2;
  548.             else if (eq(p, "{") || eq(p, "{}"))
  549.                 continue;
  550.         while (c = *p++)
  551.             (*f)(c);
  552.     }
  553. }
  554. /*
  555. static
  556. scan(t, f)
  557.     register char **t;
  558.     int (*f)();
  559. {
  560.     register char *p, c;
  561.  
  562.     while (p = *t++)
  563.         while (c = *p)
  564.             *p++ = (*f)(c);
  565. } */
  566.  
  567. static
  568. tglob(c)
  569.     register char c;
  570. {
  571.  
  572.     if (any(c, globchars))
  573.         gflag |= c == '{' ? 2 : 1;
  574.     return (c);
  575. }
  576. /*
  577. static
  578. trim(c)
  579.     char c;
  580. {
  581.  
  582.     return (c & TRIM);
  583. } */
  584.  
  585.  
  586. letter(c)
  587.     register char c;
  588. {
  589.  
  590.     return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
  591. }
  592.  
  593. digit(c)
  594.     register char c;
  595. {
  596.  
  597.     return (c >= '0' && c <= '9');
  598. }
  599.  
  600. any(c, s)
  601.     register int c;
  602.     register char *s;
  603. {
  604.  
  605.     while (*s)
  606.         if (*s++ == c)
  607.             return(1);
  608.     return(0);
  609. }
  610. blklen(av)
  611.     register char **av;
  612. {
  613.     register int i = 0;
  614.  
  615.     while (*av++)
  616.         i++;
  617.     return (i);
  618. }
  619.  
  620. char **
  621. blkcpy(oav, bv)
  622.     char **oav;
  623.     register char **bv;
  624. {
  625.     register char **av = oav;
  626.  
  627.     while (*av++ = *bv++)
  628.         continue;
  629.     return (oav);
  630. }
  631.  
  632. blkfree(av0)
  633.     char **av0;
  634. {
  635.     register char **av = av0;
  636.  
  637.     while (*av)
  638.         free(*av++);
  639. }
  640.  
  641. static
  642. char *
  643. strspl(cp, dp)
  644.     register char *cp, *dp;
  645. {
  646.     register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
  647.  
  648.     if (ep == (char *)0)
  649.         fatal("Out of memory");
  650.     (void) strcpy(ep, cp);
  651.     (void) strcat(ep, dp);
  652.     return (ep);
  653. }
  654.  
  655. char **
  656. copyblk(v)
  657.     register char **v;
  658. {
  659.     register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
  660.                         sizeof(char **)));
  661.     if (nv == (char **)0)
  662.         fatal("Out of memory");
  663.  
  664.     return (blkcpy(nv, v));
  665. }
  666.  
  667. static
  668. char *
  669. strend(cp)
  670.     register char *cp;
  671. {
  672.  
  673.     while (*cp)
  674.         cp++;
  675.     return (cp);
  676. }
  677. /*
  678.  * Extract a home directory from the password file
  679.  * The argument points to a buffer where the name of the
  680.  * user whose home directory is sought is currently.
  681.  * We write the home directory of the user back there.
  682.  */
  683. gethdir(home)
  684.     char *home;
  685. {
  686.     register struct passwd *pp = getpwnam(home);
  687.  
  688.     if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
  689.         return (1);
  690.     (void) strcpy(home, pp->pw_dir);
  691.     return (0);
  692. }
  693.  
  694. static
  695. fatal(s)
  696. char *s;
  697. {
  698.     fprintf( stderr, "glob: %s\n", s );
  699.     exit(1);
  700. }
  701.